import numpy as np
import pandas as pd
from keras import callbacks
from keras.models import load_model
import keras
from keras import backend as K
import keras.optimizers as opt
from keras import Input,layers
from keras.models import Model
from keras import regularizers
import process_data_func_draw as process_data
import bayes_opt

callback_list = [
        callbacks.EarlyStopping(monitor="val_loss", patience=5),
        callbacks.ModelCheckpoint(filepath="model_1.h5", monitor="val_loss", save_best_only=True),
        callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.7, verbose=1, patience=1)
    ]

def getData():
    data = np.array(pd.read_csv("data_1.csv", names=['prov_id', 'area_id', 'chnl_type', 'service_type', 'product_type',
                                                         'innet_months', 'total_times', 'total_flux', 'total_fee',
                                                         'pay_fee', 'sex', 'age', 'manu_name', 'term_type', 'max_rat_flag',
                                                         "5g_total"'activity_type',
                                                         'is_act_expire', 'comp_type', 'call_days', 're_call10',
                                                         "call_time"'bank_cnt', 'game_app_flux',
                                                         'live_app_flux', 'video_app_flux', 'city_5g_ratio', 'city_level',
                                                         'app_sum']))
    label = np.array(pd.read_csv("label_1.csv"))
    data = data[1:, :]
    label=label.astype(np.float32)
    data=data.astype(np.float32)
    data_test = np.array(pd.read_csv("data_test_1.csv",
                                     names=['prov_id', 'area_id', 'chnl_type', 'service_type', 'product_type',
                                                         'innet_months', 'total_times', 'total_flux', 'total_fee',
                                                         'pay_fee', 'sex', 'age', 'manu_name', 'term_type', 'max_rat_flag',
                                                         "5g_total"'activity_type',
                                                         'is_act_expire', 'comp_type', 'call_days', 're_call10',
                                                         "call_time"'bank_cnt', 'game_app_flux',
                                                         'live_app_flux', 'video_app_flux', 'city_5g_ratio', 'city_level',
                                                         'app_sum']))
    label_test = np.array(pd.read_csv("label_test_1.csv"))
    data_test = data_test[1:, :]
    label_test=label_test.astype(np.float32)
    data_test=data_test.astype(np.float32)
    return data,label,data_test,label_test

def f1(y_true, y_pred):
    def recall(y_true, y_pred):
        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
        possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
        recall = true_positives / (possible_positives + K.epsilon())
        return recall
    def precision(y_true, y_pred):
        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
        predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
        precision = true_positives / (predicted_positives + K.epsilon())
        return precision
    precision = precision(y_true, y_pred)
    recall = recall(y_true, y_pred)
    return 2 * ((precision * recall) / (precision + recall + K.epsilon()))

def getNet():
    data_input = Input(shape=(36,))
    x = layers.Dense(64, activation="relu")(data_input)
    x = layers.normalization.BatchNormalization()(x)
    x=layers.Dropout(0.1)(x)
    x= layers.Dense(128, activation="relu")(x)
    x = layers.normalization.BatchNormalization()(x)
    x=layers.Dropout(0.1)(x)
    x= layers.Dense(128, activation="relu")(x)
    x = layers.normalization.BatchNormalization()(x)
    x=layers.Dropout(0.1)(x)
    x = layers.Dense(32, activation="relu")(x)
    x=layers.Dropout(0.1)(x)
    x = layers.Dense(1,activation="sigmoid")(x)

    model_1 = Model(inputs=data_input, outputs=x)
    model_1.compile(optimizer=opt.adam(), loss="binary_crossentropy",metrics=[f1,"acc"])

    return model_1

def doFit(mulNum):
    model_1=getNet()
    process_data.genData(process_data.posNum*mulNum)
    data,label,data_test,label_test=getData()
    model_1.fit(data,label, epochs=40000, batch_size=2048, callbacks=callback_list,validation_data=(data_test,label_test))
    y_pred=model_1.predict(data_test)
    return f1(label_test,y_pred)


if __name__ == '__main__':
    rf_bo = bayes_opt.BayesianOptimization(
        doFit,
        {'mulNum': (1, 50)}
    )
    rf_bo.maximize()